package com.gitee.wsl.statemachine

import com.gitee.wsl.statemachine.action.ActionHandler
import com.gitee.wsl.statemachine.action.StateActionScope
import com.gitee.wsl.statemachine.transition.StateMachineActionFlow
import com.gitee.wsl.statemachine.trigger.ActionTriggerConfig
import com.gitee.wsl.statemachine.trigger.ActionTriggerFun
import com.gitee.wsl.statemachine.trigger.ActionTriggerScope
import com.gitee.wsl.statemachine.trigger.SampleActionTrigger
import timber.log.Timber

typealias Reducer<A , State> = suspend StateMachineContext<A, State>.(action: A, state: State) -> Unit

typealias StateMonitor<A , State> = suspend StateMachineScope<A>.(state: State) -> Unit

class StateMachineConfig<A, State>(val initialState: State){

    var reducer:Reducer<A,State>  = { action, state-> Timber.d("reducer action:${action} state:${state}")}

    var onStateChanged: StateMonitor<A , State>?=null

    val actionTriggerMap = mutableMapOf<State, SampleActionTrigger<State>>()

    val stateFlowList = mutableListOf<StateMachineActionFlow<A, State>>()

    private fun addStateFlow(fromState:State, action: A, toState: State, block: () -> Unit={}){
        stateFlowList.add(StateMachineActionFlow(fromState, action, toState, block))
    }

    fun stateActionTrigger(state:State, actionHandler: ActionTriggerConfig<State>.()->Unit){
        val actionConfig= ActionTriggerConfig<State>()
        actionHandler(actionConfig)
        actionTriggerMap[state] = SampleActionTrigger(state, actionConfig)
    }

     fun state(state:State, actionHandler: ActionHandler<A, State>){
         val actionConfig = ActionTriggerConfig<State>()

         val scope = object: StateActionScope<A, State> {
             override fun action(action: A, toState: State) {
                addStateFlow(state,action,toState)
             }

             override fun action(action: A, toState: State, actionBlock: () -> Unit) {
                 addStateFlow(state,action,toState,actionBlock)
             }

             override fun action(pair: Pair<A, State>) {
                 action(pair.first,pair.second)
             }

             override fun action(pair: Pair<A, State>,actionBlock: () -> Unit) {
                 action(pair.first,pair.second,actionBlock)
             }

             override fun trigger(actionTrigger: ActionTriggerScope<State>.() -> Unit) {
                 val scope = object: ActionTriggerScope<State> {
                     override fun tryAction(block: (beforeState: State, toState: State) -> Boolean) {
                         actionConfig.tryActionHandler = block
                     }

                     override fun before(block: ActionTriggerFun<State>) {
                         actionConfig.beforeHandler=block
                     }

                     override fun entry(block: ActionTriggerFun<State>) {
                         actionConfig.entryHandler=block
                     }

                     override fun after(block:ActionTriggerFun<State>) {
                        actionConfig.afterHandler=block
                     }

                     override fun leave(block: ActionTriggerFun<State>) {
                         actionConfig.leaveHandler=block
                     }
                 }

                 actionTrigger(scope)

                 actionTriggerMap[state] = SampleActionTrigger(state, actionConfig)
             }
         }
         actionHandler(scope)
     }
}